<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="../../../resources/styles.css">
    <link rel="icon" type="image/x-icon" href="../../../resources/favicon.ico">
    <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
    <title>Components | Hello world</title>
    <style>
      body {
        margin: 0;
        padding: 0;
      }
      .full-screen {
        width: 100vw;
        height: 100vh;
        position: relative;
        overflow: hidden;
      }
    </style>
</head>
<body>
<div class="full-screen" id="container"></div>
<script type="importmap">
    {
      "imports": {
        "three": "https://unpkg.com/three@0.160.1/build/three.module.js",
        "three/examples/jsm/lines/LineMaterial": "https://unpkg.com/three@0.160.1/examples/jsm/lines/LineMaterial.js",
        "three/examples/jsm/libs/lil-gui.module.min": "https://unpkg.com/three@0.160.1/examples/jsm/libs/lil-gui.module.min.js",
        "stats.js/src/Stats.js": "https://unpkg.com/stats-js@1.0.1/src/Stats.js"
      }
    }


</script>
<script type="module">
    import * as THREE from 'three';
    import Stats from 'stats.js/src/Stats.js';
    import * as OBC from '../../../resources/openbim-components.js';
    import * as dat from 'three/examples/jsm/libs/lil-gui.module.min';
    import {LineMaterial} from 'three/examples/jsm/lines/LineMaterial';

    const container = document.getElementById('container');

    const components = new OBC.Components();

    components.scene = new OBC.SimpleScene(components);
    const renderer = new OBC.PostproductionRenderer(components, container);
    components.renderer = renderer;

    const camera = new OBC.OrthoPerspectiveCamera(components);
    components.camera = camera;
    components.camera.controls.setLookAt(12, 6, 8, 0, 0, -10);

    components.raycaster = new OBC.SimpleRaycaster(components);

    components.init();

    const {postproduction} = renderer;
    postproduction.enabled = true;

    const scene = components.scene.get();

    components.scene.setup();

    const grid = new OBC.SimpleGrid(components, new THREE.Color(0x666666));
    const gridMesh = grid.get();
    postproduction._customEffects.excludedMeshes.push(gridMesh);

    const culler = new OBC.ScreenCuller(components);

    const fragments = new OBC.FragmentManager(components);

    // Set up fragment culler update

    container.addEventListener('mouseup', () => culler.elements.needsUpdate = true);
    container.addEventListener('wheel', () => culler.elements.needsUpdate = true);

    // Load the fragments

    const file = await fetch('../../../resources/small.frag');
    const data = await file.arrayBuffer();
    const buffer = new Uint8Array(data);
    const model = await fragments.load(buffer);

    for(const fragment of model.items) {
        culler.elements.add(fragment.mesh);
    }

    const properties = await fetch('../../../resources/small.json');
    model.setLocalProperties(await properties.json());

    culler.elements.needsUpdate = true;

    const clipper = new OBC.EdgesClipper(components);
    const thickMaterial = new THREE.LineBasicMaterial({color: 'black'});
    const thinMaterial = new THREE.LineBasicMaterial({color: 'blue'});
    const fillMaterial = new THREE.MeshBasicMaterial({color: 'gray', side: 2});
    const fillOutline = new THREE.MeshBasicMaterial({color: 'black', side: 1, opacity: 0.5, transparent: true});

    clipper.styles.create("projected", new Set(), thinMaterial);
    clipper.styles.create("filled", new Set(), thickMaterial, fillMaterial, fillOutline);
    const styles = clipper.styles.get();

    postproduction.customEffects.outlineEnabled = true;

    const classifier = new OBC.FragmentClassifier(components);
    classifier.byEntity(model);

    const found = classifier.find({entities: ["IFCWALLSTANDARDCASE", "IFCWALL"]});

    for (const fragID in found) {
        const {mesh} = fragments.list[fragID];
        styles.filled.fragments[fragID] = new Set(found[fragID]);
        styles.filled.meshes.add(mesh);
    }

    const meshes = [];
    for (const fragment of model.items) {
        const {mesh} = fragment;
        meshes.push(mesh);
        styles.projected.meshes.add(mesh);
    }

    const whiteColor = new THREE.Color("white");
    const whiteMaterial = new THREE.MeshBasicMaterial({color: whiteColor});
    const materialManager = new OBC.MaterialManager(components);
    materialManager.addMaterial("white", whiteMaterial);
    materialManager.addMeshes("white", meshes);

    const plans = new OBC.FragmentPlans(components, clipper, components.camera);
    await plans.computeAllPlanViews(model);

    classifier.byStorey(model);


    const mainToolbar = new OBC.Toolbar(components);
    components.ui.addToolbar(mainToolbar);

    mainToolbar.addChild(plans.uiElement.get("main"));

    plans.onNavigated.add(() => {
        postproduction.customEffects.glossEnabled = false;
        materialManager.setBackgroundColor(whiteColor);
        materialManager.set(true, ["white"]);
        grid.visible = false;
    });

    plans.onExited.add(() => {
        postproduction.customEffects.glossEnabled = true;
        materialManager.resetBackgroundColor();
        materialManager.set(false, ["white"]);
        grid.visible = true;
    });

    const dxfExporter = new OBC.DXFExporter(components);

    plans.commands = {
        "Export to DXF": async (plan) => {
            const link = document.createElement("a");
            const result = await dxfExporter.export(plan.name);
            const fileName = `${plan.name}.dxf`;
            const file = new File([new Blob([result])], fileName);
            link.href = URL.createObjectURL(file);
            link.download = fileName;
            link.click();
            link.remove();
        },
    }

    await plans.updatePlansList();

    for(const {mesh} of model.items) {
        if(mesh.material[0].opacity !== 1) {
            mesh.material[0].depthWrite = false;
            mesh.material[0].polygonOffset = true;
            mesh.material[0].polygonOffsetFactor = 5;
            mesh.material[0].polygonOffsetUnits = 1;
        }
    }


    // Set up stats
    const stats = new Stats();
    stats.showPanel(2);
    document.body.append(stats.dom);
    stats.dom.style.left = '0px';
    stats.dom.style.right = 'auto';

    components.renderer.onBeforeUpdate.add(() => stats.begin());
    components.renderer.onAfterUpdate.add(() => stats.end());

</script>
</body>
</html>